import re

"""
re.match函数:
尝试从字符串的起始位置匹配一个模式，如果不是起始位置匹配成功，则 match()返回 None
    语法：
    re.match(pattern, string, flags=0)
    参数说明：
    1.pattern: 匹配的正则表达式
    2.String 要匹配的字符串
    3.flags 标志位，用于控制正则表达式的匹配方式
使用group(Num) 或 groups() 匹配对象函数来获取匹配表达式
    1.group(num=0): 匹配的整个表达式的字符串，group() 可以一次输入多个组号，在这种情况下将返回一个包含那些组所对应值的元组
    2.groups(): 返回一个包含所有小组字符串的元组，从1到所包含的小组号
"""
print('---------------------Match---------------------')
# match
print(re.match('www', 'www.runoob.com').span())  # 在起始位置匹配 .span 返回下标
print(re.match('com', 'www.runoob.com'))  # 不在起始位置匹配
# group / groups
line = "Cats are smarter than dogs"
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)

if matchObj:
    print('matchObj.groups(): ', matchObj.groups())
    print('matchObj.group(nums): ', matchObj.group(1, 2))
else:
    print('No match')

"""
re.search方法:
扫描整个字符串并返回第一个成功的匹配
    语法:
    re.search(pattern, string, flags=0)
    参数说明:
    1.pattern: 匹配的正则表达式
    2.String 要匹配的字符串
    3.flags 标志位，用于控制正则表达式的匹配方式
使用group(Num) 或 groups() 匹配对象函数来获取匹配表达式
    1.group(num=0): 匹配的整个表达式的字符串，group() 可以一次输入多个组号，在这种情况下将返回一个包含那些组所对应值的元组
    2.groups(): 返回一个包含所有小组字符串的元组，从1到所包含的小组号
"""
print('---------------------Search---------------------')
# search
print(re.search('www', 'www.runoob.com').span())  # 在起始位置匹配 .span 返回下标
print(re.search('com', 'www.runoob.com').span())  # 不在起始位置匹配
# group / groups
line = "Cats are smarter than dogs"
matchObj = re.search(r'(.*) are (.*?) .*', line, re.M | re.I)

if matchObj:
    print('matchObj.groups(): ', matchObj.groups())
    print('matchObj.group(nums): ', matchObj.group(1, 2))
else:
    print('No match')

"""
检索和替换
Python 的re模块提供了re.sub用于替换字符串中的匹配项
    语法：
    re.sub(pattern, repl, string, count=0, flags=0)
    参数：
    1.pattern: 正则中的模式字符串
    2.repl: 替换的字符串，也可为一个函数
    3.string: 要被查找替换的原始字符串
    4.count: 模式匹配后替换的最大次数，默认0表示替换所有的匹配
    5.flags: 编译时用的匹配模式，数字形式
前三个为必选参数，后两个为可选参数
"""
print('---------------------Sub---------------------')
phone = '2004-959-559 # 这是一个电---话号码'
# 删除注释
num = re.sub(r'#.*$', '', phone)
print('电话号码：', num)
# 移除非数字内容
num = re.sub(r'\D', '', phone)
print('电话号码：', num)


def double(matched):
    value = int(matched.group('value'))
    return str(value * 2)


# repl 可为函数
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))  # ?<value> 命名捕获组, 通过指定的名称获取匹配到的字串

"""
compile函数
用于编译正则表达式，生成一个正则表达式(Pattern)对象,供match()和search()两个函数使用
    语法：
    re.compile(pattern[, flags])
    参数：
    1.pattern: 一个字符串形式的正则表达式
    2.flags可选，表示匹配模式,比如忽略大小写，多行模式等，具体参数为:
        re.IGNORECASE 或 re.I - 使匹配对大小写不敏感
        re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
        re.MULTILINE 或 re.M - 多行模式，改变 ^ 和 $ 的行为，使它们匹配字符串的每一行的开头和结尾。
        re.DOTALL 或 re.S - 使 . 匹配包括换行符在内的任意字符。
        re.ASCII - 使 \w, \W, \b, \B, \d, \D, \s, \S 仅匹配 ASCII 字符。
        re.VERBOSE 或 re.X - 忽略空格和注释，可以更清晰地组织复杂的正则表达式。
        可单独使用,也可以按位或(|)组合使用
"""
print('---------------------compile---------------------')
pattern1 = re.compile(r'\d+')  # 匹配至少一个数字
m1 = pattern1.match('one12twothree34four')  # 查找头部，没有匹配
print(m1)
m1 = pattern1.match('one12twothree34four', 2, 10)  # 从'e'的位置开始匹配，没有匹配
print(m1)
m1 = pattern1.match('one12twothree34four', 3, 10)  # 从'1'的位置开始匹配，正好匹配
print(m1)  # 返回一个 Match 对象
print(m1.group(0))
print(m1.start(0))
print(m1.end(0))
m1.span(0)

pattern2 = re.compile(r'([a-z]+) ([a-z]+)', re.I)
m2 = pattern2.match('Hello World Wide Web')
print(m2)
print(m2.group(0))
print(m2.span(0))
print(m2.group(1))
print(m2.span(1))
print(m2.group(2))
print(m2.span(2))
print(m2.groups())
try:
    print(m2.group(3))
except IndexError:
    print('Error: 索引错误')

"""
findall函数
在字符串中找到正则表达式所匹配的所有子串，并返回一个列表，如果有多个匹配模式，则返回元组列表，如果没有找到匹配的，则返回空列表。
注意： match 和 search 是匹配一次 findall 匹配所有。
    语法：
    re.findall(pattern, string, flags=0)
    或
    pattern.findall(string[, pos[, endpos]])
    参数:
    pattern 匹配模式。
    string 待匹配的字符串。
    pos 可选参数，指定字符串的起始位置，默认为 0。
    endpos 可选参数，指定字符串的结束位置，默认为字符串的长度。
"""
print('---------------------findall---------------------')
result1 = re.findall(r'\d+', 'rumoob 123 google 456')

pattern = re.compile(r'\d+')  # 查找数字
result2 = pattern.findall('runoob 123 google 456')
result3 = pattern.findall('run88oob123google456', 0, 10)

print(result1)
print(result2)
print(result3)

result = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
print(result)

"""
finditer函数
和 findall 类似，在字符串中找到正则表达式所匹配的所有子串，并把它们作为一个迭代器返回。
    语法：
    re.finditer(pattern, string, flags=0)
    参数：
    1.pattern: 	匹配的正则表达式
    2.string: 要匹配的字符串
    3.flags: 标志位，用于控制正则表达式的匹配方式，如：是否区分大小写，多行匹配等等
"""
print('---------------------finditer---------------------')
it = re.finditer(r"\d+", "12a32bc43jf3")
for match in it:
    print(match.group())

"""
split函数
split 方法按照能够匹配的子串将字符串分割后返回列表
    语法:
    re.split(pattern, string[, maxsplit=0, flags=0])
    参数:
    1.pattern: 匹配的正则表达式
    2.string: 要匹配的字符串
    3.maxsplit: 分割次数，maxsplit=1 分割一次，默认为 0，不限制次数
    4.flags: 标志位，用于控制正则表达式的匹配方式，如：是否区分大小写，多行匹配等等
"""
print('---------------------split---------------------')
print(re.split('\W+', 'runoob, runoob, runoob.'))
print(re.split('(\W+)', ' runoob, runoob, runoob.'))
print(re.split('\W+', ' runoob, runoob, runoob.', 1))
print(re.split('a*', 'hello world'))  # 对于一个找不到匹配的字符串而言，split 不会对其作出分割
